package com.yesep.learn.netty.server.listener;

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.yesep.learn.netty.protocol.common.Constants;
import com.yesep.learn.netty.server.adapter.ServerChannelHandlerAdapter;
import com.yesep.learn.netty.server.config.NettyServerConfig;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

/**
 * Netty服务器监听器
 */
@Component
public class NettyServerListener {
	private static final Logger log = LoggerFactory.getLogger(NettyServerListener.class);

	private ServerBootstrap serverBootstrap = new ServerBootstrap();// 创建bootstrap
	private EventLoopGroup boss = new NioEventLoopGroup();// BOSS
	private EventLoopGroup work = new NioEventLoopGroup();// Worker
	@Resource
	private ServerChannelHandlerAdapter channelHandlerAdapter;// 通道适配器
	@Resource
	private NettyServerConfig nettyConfig;// NETTY服务器配置类

	/**
	 * 开启及服务线程
	 */
	public void start() {
		serverBootstrap.group(boss, work).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO));
		try {
			// 设置事件处理
			serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) {
					ChannelPipeline pipeline = ch.pipeline();
					ByteBuf delimiter = Unpooled.copiedBuffer(Constants.PKG_FOOTER.getBytes());//包尾,固定为<CR><LF>（回车，换行）
					pipeline.addLast("frameDecoder", new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, delimiter));
					Charset charset = Charset.forName(Constants.CHARSET);
					pipeline.addLast(new StringDecoder(charset));// 进行字符串的编解码设置
					pipeline.addLast(new StringEncoder(charset));
					pipeline.addLast(new IdleStateHandler(nettyConfig.getHeartbeatTimeout(), 0, 0, TimeUnit.SECONDS));// 添加心跳支持
					pipeline.addLast(channelHandlerAdapter);
				}
			});
			int port = nettyConfig.getPort();// 从配置文件中(application.yml)获取服务端监听端口号
			log.info("netty服务器在[{}]端口启动监听", port);
			ChannelFuture cf = serverBootstrap.bind(port).sync();
			cf.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			log.error("[出现异常] 释放资源");
			boss.shutdownGracefully();
			work.shutdownGracefully();
		}
	}

	/**
	 * 关闭服务器方法
	 */
	@PreDestroy
	public void close() {
		log.info("关闭服务器....");
		boss.shutdownGracefully();
		work.shutdownGracefully();
	}
}
